pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Build'
}
}
stage('Test') {
steps {
echo 'Test'
}
}
stage('Deploy') {
steps {
echo 'Deploy'
}
}
}
}NightClazz Lille - 4 Décembre 2017
Damien DUPORTAL & Jean-Marc MEESSEN
Training Engineer @ CloudBees
Docker & Apple fanboy.
Human stack focused
Rock climber
Contact:
Twitter: @DamienDuportal
Github: dduportal
eMail: damien.duportal@gmail.com
Customer Success Manager @ CloudBees
Explorer of the great things out there
Loves to share his discoveries
Not too old for great adventures
Contact:
Twitter: @JM_Meessen
Github: jmMeessen
eMail: jean-marc@meessen-web.org
Y a-t-il des développeurs ici ?
Qui pratique l’Intégration Continue ?
Avec quels outils ?
Jenkins "Old School" ? / "New Generation" ?
GitLab ? TeamCity ? TravisCI ? Bamboo ?
Autre ?
Présentation générale
Jenkins Pipelines
Blue Ocean
Donner des pistes d’exploration
Mais c’est mieux avec un atelier (Lab)
Chaque intégration est validée par un build automatisé (avec tests)
Le code est intégré souvent, au moins journellement, pour que l’intégration soit un non-event
Construire et intégrer le code en continu, avec une boucle de feedback
Logiciel Open Source
Orchestrateur de tâches
Un des tout premiers moteur d’intégration continue
Architecture centrée sur les plugins
Un gigantesque écosystème
Pierre angulaire de l’évolution de Jenkins
Visualisation et manipulation de "Pipelines"
GUI moderne, se concentrant sur les actions principales
Un outil pour définir votre flux de Continuous Delivery/Deployment avec votre code
!= outil de création de job comme "Job DSL"
Réduit le nombre de jobs nécessaires
Spécification facilitée par du "code"
Survi au redémarrage du Jenkins Master
Le Pipeline est décrit dans un fichier texte: le JenkinsFile
DSL spécifique
stocké dans un SCM
versionné
isolation par branche
suit les patterns à la “Git / Github / Gitlab flow”
Pipeline-as-code: Nous avons besoin d’un Jenkinsfile
Par où commencer ?
Declarative
Syntaxe par défaut
S’utilise avec Blue Ocean
Scripted
Syntaxe originale (~3 ans)
"Great Power == Great Responsibility"
À utiliser lorsque le Déclaratif commence à être bizarre
Fourni le cycle ("round trip") complet avec le SCM
Pas de Pipeline ? "Suivez le guide".
Le Pipeline existe déjà ? Edit, commit, et exécutez le
Get the AWS DNS name of your machine
Open the URL YOUR_INSTANCE_DNS:10000
Welcome to the Lab Home Page
Click the link Workshop Slides
Browse to this current slide
Access the Gitea git server:
Log in as the user butler (password is the same)
Access the source code:
Once authenticated, click on Explore (on top)
Click on butler/demoapp
Direct link: http://localhost:10000/gitserver/butler/demoapp
Access your Jenkins instance:
Log in as the user butler (password is the same)
This is the "Jenkins Classic GUI"
Switch to Blue Ocean:
Or click on the item "Open Blue Ocean", on the left menu
Create a new Pipeline, with the following properties:
Stored in Git
Get the SSH URL from the git server
Configure Jenkins access to the source code:
In Gitea, click the top-right user drop down
Browse to SSH/GPG Keys
Add a new key, by copy and pasting from Jenkins
Click the button Create a Pipeline
Use the Blue Ocean Pipeline Editor and Gitea git server
Create a Pipeline that have 3 stages: Build, Test and Deploy
Each stage has 1 step that prints a message
"Building…" for Build, "Testing…" for Test…
Save, add a commit message and see the build kicking off
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Build'
}
}
stage('Test') {
steps {
echo 'Test'
}
}
stage('Deploy') {
steps {
echo 'Deploy'
}
}
}
}Using the Blue Ocean Pipeline Editor:
Edit the current Pipeline’s 3 stages to run scripts
Scripts are stored in the ./scripts folder (in SCM)
Use the step Shell Script (keyword sh)
Remove the echo steps
Save, add a commit message and see the build kicking off
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './scripts/build.sh'
}
}
stage('Test') {
steps {
sh './scripts/test.sh'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}Using the Blue Ocean Pipeline Editor:
Edit the current Pipeline
Build stage should archive all *.jar files found in ./target
Test stage should publish the junit test reports
Found in ./target. TIP for recusrive: */.xml
Save, add a commit message and see the build kicking off
Build should be UNSTABLE
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './scripts/build.sh'
archiveArtifacts 'target/*.jar'
}
}
stage('Test') {
steps {
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}Le build est en état UNSTABLE (jaune)
Priorité: réparer le build
Utiliser Gitea git server
Les tests d’intégration sont dans src/tests/java/hello
Indices:
Integration Tests: == IT
Il suffit de savoir commenter/dé-commenter
Depuis src/test/java/hello/HelloControllerIT.java
Cliquer sur "Edit"
Commenter la ligne 39
Dé-commenter la ligne 40
Commit avec un message (push automatique)
Lancer le build manuellement dans Blue Ocean
Le build doit être vert (Stable)
Nous avons dû lancer le build manuellement
IC: Retours rapides !
Lancer le build dès que le code est poussé
Configurons un "Webhook" :
Depuis Gitea git server → Settings → Webhooks
Ajouter un nouveau webhook:
Type: Gitea
When should this webhook be triggered?: I need everything
Payload URL: http://localhost:10000/jenkins/job/demoapp/build?delay=0
Ajoutez un commentaire dans le Jenkinsfile depuis Gitea git server
Un build va démarrer
Validez dans l’onglet "Changes"
Dans l’éditeur Blue Ocean, voir la version textuelle:
Combinaison CTRL + S (On Mac: CMD +S)
Bi-directionnel: essayez de charger une solution de pipeline
Le Pipeline Syntax Snippet Generator comme acolyte:
Génération dynamique en fonction de vos plugins
Depuis l’interface "ancienne" de Jenkins
Menu de gauche de votre job "Pipeline" (ou MultiBranch)
But: réutiliser les binaires générés dans Build
Action: "mise sur étagère": Stash / Unstash
Modifier le Pipeline pour :
"Stasher" le dossier target, à la fin de la phase Build
"Unstasher" au début de la phase Test
Attention, une limite de l’éditeur Blue Ocean va être atteinte
L’éditeur Blue Ocean ne supporte pas encore le ré-ordonnancement de "stages"
Mode textuel et/ou Snippet Generator à utiliser
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './scripts/build.sh'
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
stage('Test') {
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}Section post :
Contient des "steps" à exécuter à la fin du Pipeline ou après une "stage"
Divisé en "condition d’états":
always, success, failure, changed
Chaque condition contient ses propres "steps"
Pas encore intégré dans l’éditeur Blue Ocean
Si le "stage" Build échoue, alors la tâche "archiveArtifacts" ne devrait pas être exécutée
Même chose pour stash
Le rapports de tests unitaires doivent être publiés dans tous les cas
Format Junit
Stockés dans ./target/surefire-reports/*/.xml
Utiliser la documentation:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/surefire-reports/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}Un noeud (ou node) est une machine prête à recevoir des builds
Step agent spécifie sur quel "noeud" exécuter des "stages".
Une section agent globale doit être définie
(au niveau du block pipeline)
On peut aussi définire des sections agent par "stage"
Exécuter l’étape Build sur un agent
configuré avec le label maven-jdk8
Exécuter l’étape Test sur un agent
configuré avec le label java8
L’éditeur Blue Ocean est utilisable
pipeline {
agent any
stages {
stage('Build') {
agent {
node {
label 'maven-java8'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/surefire-reports/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
agent {
node {
label 'java8'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}But: Tester en parallèle l’application sur java 7 et 8
Mot clef parallel définissant un block contenant
des "stages"
Agent java7 pour le Test Java 7
L’éditeur Blue Ocean est utilisable (et recommandé)
pipeline {
agent any
stages {
stage('Build') {
agent {
node {
label 'maven-java8'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/surefire-reports/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
node {
label 'java8'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}But: Usage de Docker pour faciliter la définition des environements de build
Le mot clef agent permet d’exécuter les "stages" dans
un container Docker, depuis une "image Docker",
ou depuis un Dockerfile (recette maison d’image Docker)
Exécuter le Build dans un containeur
basé sur le fichier Dockerfile.build
Exécuter le Test Java 8 dans un containeur
basé sur les images maven:3-jdk-8-alpine
Trick: documentation manquante sur filename,
dans un block dockerfile
pipeline {
agent any
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/surefire-reports/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}